package models

import (
	"context"
	"fmt"
	"github.com/redis/go-redis/v9"
	"github.com/spf13/viper"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
	"log"
	"os"
	"time"
)

const (
	dbMysql = "mysql"
)

var (
	Db          *gorm.DB
	RedisClient *redis.Client
)

// Database 在初始化mysql链接
func Database() {
	Db = conn(viper.GetString("mysql"), dbMysql)
}

func Redis() {
	redisOptions := &redis.Options{
		Addr:         viper.GetString("redis.host"),
		Password:     viper.GetString("redis.password"),
		DB:           viper.GetInt("redis.db"),
		PoolSize:     30,
		MinIdleConns: 30,
	}
	if viper.GetString("redis.username") != "" {
		redisOptions.Username = viper.GetString("redis.username")
	}
	client := redis.NewClient(redisOptions)

	_, err := client.Ping(context.Background()).Result()

	if err != nil {
		log.Panicf("连接Redis不成功%v\n", err)
	}

	RedisClient = client
}

// conn 在初始化mysql链接
func conn(connString, dbType string) *gorm.DB {
	if connString == "" {
		log.Panic(fmt.Sprintf("数据库配置不能为空: %s", connString))
	}
	// 初始化GORM日志配置
	var LogLevel logger.LogLevel
	switch viper.GetString("gorm.log_level") {
	case "silent":
		LogLevel = logger.Silent
	case "error":
		LogLevel = logger.Error
	case "warn":
		LogLevel = logger.Warn
	case "info":
		LogLevel = logger.Info
	}
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer
		logger.Config{
			SlowThreshold:             time.Second, // Slow SQL threshold
			LogLevel:                  LogLevel,    // Log level
			IgnoreRecordNotFoundError: true,        // Ignore ErrRecordNotFound error for logger
			Colorful:                  true,        // Disable color
		},
	)
	var db *gorm.DB
	var err error
	switch dbType {
	case dbMysql:
		db, err = gorm.Open(mysql.Open(connString), &gorm.Config{
			Logger: newLogger,
			NamingStrategy: schema.NamingStrategy{
				SingularTable: true, // 使用单数表名
			},
		})
	default:
		log.Panic(fmt.Sprintf("数据库类型错误, db lost: %v", err))
	}

	sqlDB, err := db.DB()
	if err != nil {
		log.Panic(fmt.Sprintf("初始化数据库失败, db lost: %v", err))
	}
	//设置连接池
	sqlDB.SetMaxIdleConns(10)  //空闲
	sqlDB.SetMaxOpenConns(100) //打开

	return db

}
